package com.yenlien.traceyun.business.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yenlien.traceyun.business.dao.*;
import com.yenlien.traceyun.business.entity.*;
import com.yenlien.traceyun.business.interceptor.UserAuthUtil;
import com.yenlien.traceyun.webase.exception.BusinessException;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by LiuSha on 2020/7/29.
 */
@Service
public class StorageManageService {
    @Autowired
    private StorageManageDao storageManageDao;
    @Autowired
    private StorageManageDetailedDao storageManageDetailedDao;
    @Autowired
    private StorageManageCuringService storageManageCuringService;

    @Autowired
    private ClientOrderDao clientOrderDao;

    @Autowired
    private ClientOrderDetailDao clientOrderDetailDao;

    @Autowired
    private LogisticsDao logisticsDao;

    @Autowired
    private WarehouseOutDao warehouseOutDao;

    @Autowired
    private WarehouseInDao warehouseInDao;

    @Autowired
    private BoxDao boxDao;
    @Autowired
    private SubpackageService subpackageService;

    @Value("${traceyun.app.id}")
    private String appId;

    /**
     * 入库
     *
     * @param storageManage
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public StorageManage in(StorageManage storageManage) {
        storageManage.setAppId(appId);
        storageManage.setCreatetime(new Date());
        StorageManage p = storageManageDao.save(storageManage);
        StorageManageDetailed detailed = new StorageManageDetailed();
        detailed.setType("入库");
        detailed.setNumber(p.getNumber());
        detailed.setSpecs(p.getSpecs());
        detailed.setSpecsUnit(p.getSpecsUnit());
        detailed.setStorageManageId(p.getId());
        detailed.setLastStep(p.getId());
        storageManageDetailedDao.save(detailed);
        return p;
    }


    public Page<StorageManage> findByList(final StorageManage storageManage) {
        storageManage.setAppId(appId);
        Pageable pageable = PageRequest.of(storageManage.getPage(), storageManage.getPageSize(), Sort.Direction.DESC, "createtime");
        return storageManageDao.findAll(new Specification<StorageManage>() {
            private static final long serialVersionUID = 1L;

            @Override
            public Predicate toPredicate(Root<StorageManage> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Path<String> companyId = root.get("companyId");
                Path<String> warehouseId = root.get("warehouseId");
                Path<String> inType = root.get("inType");
                Path<String> productName = root.get("productName");
                Path<String> cop = root.get("cop");
                //构造查询条件
                List<Predicate> list = new ArrayList<>();
                if (!StringUtils.isEmpty(storageManage.getCompanyId())) {
                    list.add(cb.equal(companyId, storageManage.getCompanyId()));
                }
                if (!StringUtils.isEmpty(storageManage.getWarehouseId())) {
                    list.add(cb.equal(warehouseId, storageManage.getWarehouseId()));
                }
                if (!StringUtils.isEmpty(storageManage.getWarehousePartId())) {
                    list.add(cb.equal(root.get("warehousePartId"), storageManage.getWarehousePartId()));
                }
                if (!StringUtils.isEmpty(storageManage.getInType())) {
                    list.add(cb.equal(inType, storageManage.getInType()));
                }
                if (!StringUtils.isEmpty(storageManage.getProductName())) {
                    list.add(cb.like(productName, "%" + storageManage.getProductName() + "%"));
                }
                if (!StringUtils.isEmpty(storageManage.getCop())) {
                    list.add(cb.equal(cop, storageManage.getCop()));
                }
                if (!StringUtils.isEmpty(storageManage.getAppId())) {
                    list.add(cb.equal(root.get("appId"), storageManage.getAppId()));
                }
                Predicate[] predicate = new Predicate[list.size()];
                Predicate pre_and = cb.and(list.toArray(predicate));
                return pre_and;
            }
        }, pageable);
    }


    /**
     * 调整库存
     *
     * @param jsonObject
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void adjustment(JSONObject jsonObject) {
        String id = jsonObject.getString("storageId");
        BigDecimal actualNum = jsonObject.getBigDecimal("actualNum");
        String remarks = jsonObject.getString("remarks");
        StorageManage storageManage = storageManageDao.findById(id);
        storageManage.setNumber(actualNum);
        StorageManageDetailed detailed = new StorageManageDetailed();
        detailed.setLastStep(id);
        detailed.setProductName(storageManage.getProductName());
        detailed.setSpecs(storageManage.getSpecs());
        detailed.setSpecsUnit(storageManage.getSpecsUnit());
        detailed.setStorageManageId(storageManage.getId());
        detailed.setCreatetime(new Date());
        detailed.setType("调整");
        if (remarks == null) {
            remarks = "";
        }
        detailed.setRemark(remarks + "【" + storageManage.getNumber() + "->" + actualNum + "】");
        detailed.setNumber(storageManage.getNumber().subtract(actualNum));
        storageManageDao.save(storageManage);
        storageManageDetailedDao.save(detailed);
    }

    /**
     * 出库
     *
     * @param logistics
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void out(Logistics logistics, JSONArray array) {
        //保存物流信息
        logisticsDao.save(logistics);
        if (array != null && array.size() > 0) {
            for (int i = 0; i < array.size(); i++) {
                JSONObject item = array.getJSONObject(i);
                String detailId = item.getString("detailId");
                ClientOrderDetailed orderDetailed = clientOrderDetailDao.findById(detailId).get();
                if (orderDetailed.isOut()) {
                    continue;
                }
                if (item.containsKey("codes")) {
                    JSONArray codeArray = item.getJSONArray("codes");
                    if (orderDetailed.getNumber() != codeArray.size()) {
                        throw new BusinessException("500", detailId + " 出库数量不对");
                    }
                    if (codeArray != null && codeArray.size() > 0) {
                        List<String> codes = codeArray.toJavaList(String.class);
                        StorageManageDetailed manageDetailed = genreateStorageMangerDetail(orderDetailed, codes);
                        genrateWarehouse(orderDetailed, codes, manageDetailed);
                        orderDetailed.setOut(true);
                        clientOrderDetailDao.save(orderDetailed);

                    } else {
                        throw new BusinessException("500", detailId + " 出库数量不对");
                    }
                } else {
                    throw new BusinessException("500", detailId + " 出库数量不对");
                }
            }
        }
    }

    /**
     * 生产出现信息
     *
     * @param orderdetailed
     * @param codes
     */
    public void genrateWarehouse(ClientOrderDetailed orderdetailed, List<String> codes, StorageManageDetailed manageDetailed) {
        List<WarehouseOut> outs = new ArrayList<>();
        for (String item : codes) {
            WarehouseOut out = new WarehouseOut();
            out.setClientOrderDetailId(orderdetailed.getId());
            out.setSourceCode(item);
            out.setStorageManageDetailId(manageDetailed.getId());
            out.setStorageManageId(orderdetailed.getRelateId());
            outs.add(out);
        }
        warehouseOutDao.saveAll(outs);
    }


    /**
     * 生成出库记录
     *
     * @param orderdetailed
     */
    public StorageManageDetailed genreateStorageMangerDetail(ClientOrderDetailed orderdetailed, List<String> codes) {
        StorageManage storageManage = storageManageDao.findById(orderdetailed.getRelateId());
        StorageManageDetailed detailed = storageManage.getDetail();
        detailed.setType("出库");
        detailed.setNumber(new BigDecimal(orderdetailed.getNumber()));
        detailed.setClientName(orderdetailed.getClientName());
        storageManage.setOutNum(storageManage.getOutNum() - 1);
        storageManage.setNumber(storageManage.getNumber().subtract(new BigDecimal(orderdetailed.getNumber())));
        storageManageDao.save(storageManage);
        return storageManageDetailedDao.save(detailed);
    }

    /**
     * 明细
     *
     * @param id
     * @return
     */
    public StorageManage findById(String id) {
        StorageManage storageManage = storageManageDao.findById(id);
        storageManage.setStorageManageDetaileds(storageManageDetailedDao.findByStorageManageId(id));
        storageManage.setStorageManageCuringList(storageManageCuringService.findByStorageManageId(id));
        return storageManage;
    }

    /**
     * 下载码
     *
     * @param type
     * @param outputStream
     * @throws IOException
     */
    public void downCodes(String type, String storageId, String storageDetailId, OutputStream outputStream) throws IOException {

        List<String> boxes = null;
        if (type.equals("in")) {
            StorageManage storageManage = storageManageDao.findById(storageId);
            //如果是采购入库
            if (storageManage.getInType().equals("0")) {
                List<WarehouseIn> inds = warehouseInDao.findByStorageManageId(storageId);
                //溯源入库
                if (storageManage.getPurchaseType().equals("0")) {
                    boxes = inds.stream().map(p -> p.getCode()).collect(Collectors.toList());
                } else {
                    boxes = boxDao.findBySubBatch(storageManage.getSourceBatch());
                }
            } else {//生产入库
                boxes = boxDao.findBySubBatch(storageManage.getSourceBatch());
            }
        } else {//获取出库的码
            boxes = warehouseOutDao.findByStorageManageDetailId(storageDetailId);
        }
        if (boxes != null && boxes.size() > 0) {
            ByteArrayOutputStream bOutput = new ByteArrayOutputStream(12);
            for (String item : boxes) {
                bOutput.write((item + "\n").getBytes());
            }
            outputStream.write(bOutput.toByteArray());
        }
    }

    public boolean checkCodeRight(String storageId, String code) {
        StorageManage storageManage = storageManageDao.findById(storageId);
        //如果是采购入库
        if (storageManage.getInType().equals("0")) {
            //溯源入库
            if (storageManage.getPurchaseType().equals("0")) {
                if (warehouseInDao.findByCode(code).size() > 0) {
                    return true;
                } else {
                    return false;
                }
            } else {
                if (boxDao.findBySourceCode(code) != null) {
                    return true;
                } else {
                    return false;
                }
            }
        } else {
            if (boxDao.findBySourceCode(code) != null) {
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * 入库
     *
     * @param storageManages
     * @param subpackage
     * @param codes
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void save(List<StorageManage> storageManages, Subpackage subpackage, List<String> codes) {
        if (storageManages != null && storageManages.size() > 0) {
            String companyId = UserAuthUtil.getLoginUser().getCompanyId();
            for (StorageManage storageManage : storageManages) {
                storageManage.setCompanyId(companyId);
                // 2022-6-9新加
                if("0".equals(storageManage.getPurchaseType())){
                    storageManage.setMaterialCode(RandomStringUtils.randomNumeric(10));  // 生产物料代码
                    storageManage.setSourceCode(codes.get(0));
                }else {
                    storageManage.setNumber(new BigDecimal(subpackage.getSpec()).multiply(new BigDecimal(subpackage.getSubNumber())));
                }
                StorageManage p = in(storageManage);
                //分包入库
                if (storageManage.getInType().equals("1")) {
                    subIn(p);
                }
                //采购入库  溯源入库和非溯源入库是采购入库类型下级分类
                else if (storageManage.getInType().equals("0")) {
                    purchaseIn(storageManage, subpackage, codes);
                } else {
                    throw new BusinessException("500", "intype类型不对");
                }
            }
        }
    }


    /**
     * 分包入库
     *
     * @param storageManage
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void subIn(StorageManage storageManage) {
        WarehouseIn in = new WarehouseIn();
        in.setCode(storageManage.getSourceBatch());
        in.setCodeType("1");
        in.setInType(storageManage.getInType());
        in.setStorageManageId(storageManage.getId());
        warehouseInDao.save(in);
    }

    /**
     * 采购入库
     */
    public void purchaseIn(StorageManage storageManage, Subpackage subpackage, List<String> codes) {

        //溯源入库
        if (storageManage.getPurchaseType().equals("0")) {
            //追溯码管理
            if (codes != null && codes.size() > 0) {
                List<WarehouseIn> warehouseIns = new ArrayList<>();
                for (String item : codes) {
                    WarehouseIn initem = new WarehouseIn();
                    initem.setInType(storageManage.getInType());
                    initem.setStorageManageId(storageManage.getId());
                    initem.setCodeType("1");
                    initem.setCode(item);   // 2022-6-9 加上的
                    warehouseIns.add(initem);
                }
                warehouseInDao.saveAll(warehouseIns);
            }
        } else {
            subpackage.setSource("采购分包");
            subpackage.setRelevanceId(storageManage.getId());
            subpackage.setLastStep(storageManage.getId());
            subpackage.setProductName(storageManage.getProductName());
            subpackage.setSpec(storageManage.getSpecs() + "");
            subpackage.setSpecUnits(storageManage.getSpecsUnit());
            subpackage.setCompanyId(UserAuthUtil.getLoginUser().getCompanyId());
            subpackage.setAppId(appId);
            //批次页面传过来
//            subpackage.setBatch(storageManage.getId());
            Subpackage p = subpackageService.subAndGenreateCode(subpackage);

            WarehouseIn in = new WarehouseIn();
            in.setInType(storageManage.getInType());
            in.setStorageManageId(storageManage.getId());
            in.setCode(subpackage.getBatch());
            //批次管理
            in.setCodeType("0");
            warehouseInDao.save(in);
        }
    }

}
